package com.qf.cloud2202.microd.controller;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;

@RestController
public class TestController {

    @HystrixCommand(fallbackMethod = "test1Fallback",commandProperties = {
            // 给该接口设置超时时间为2s
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "2000"),
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"),
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "70"),
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "5000")
    })
    @GetMapping("/test1/{flag}")
    public String test1(@PathVariable("flag") String flag) throws InterruptedException {

        System.out.println("进入业务方法了");

        if (flag.equals("0")){
            int a = 1/0;
        }

        if (flag.equals("1")){
            Thread.sleep(3000);
        }
        // 此处省略具体的业务处理流程

        return "业务正常执行了";
    }


    /**
     * 注意：降级方法要和原来的方法参数和返回值都要保持一致
     * com.netflix.hystrix.contrib.javanica.exception.FallbackDefinitionException: fallback method wasn't found: test1Fallback([class java.lang.String])
     * @param flag
     * @return
     */
    public String test1Fallback(String flag){
        System.out.println("进入降级方法了");
        return "降级方法执行了";
    }


    /**
     * 加了Hystrix注解后，该请求是在Hystrix线程池中执行的 ，线程名字：hystrix-TestController-1
     * @return
     */
    @HystrixCommand(fallbackMethod = "test2Falback"
            ,threadPoolKey = "test2Pool",   // 设置当前接口自己的线程池名字
            threadPoolProperties = {
              @HystrixProperty(name = "coreSize",value = "2"),  // 该线程池中的线程数量
              @HystrixProperty(name = "maxQueueSize",value = "2")
            })
    @GetMapping("/test2")
    public String test2(){
        System.out.println(Thread.currentThread().getName());

        return Thread.currentThread().getName();
    }

    public String test2Falback(){

        System.out.println("进入降级方法了");
        return "降级方法执行了";
    }

    /**
     * 在该接口中，发起多个请求同时访问 test2 接口
     * num代表并发量
     * @return
     */
    @GetMapping("/p/{num}")
    public String paralTest(@PathVariable("num") Integer num) throws InterruptedException {

        final RestTemplate restTemplate = new RestTemplate();


        final ArrayList<Thread> threads = new ArrayList<>();
        for (int i=0;i<num;i++){
            // 异步执行发送http请求
            final Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    final String s = restTemplate.getForObject("http://localhost:8110/test2", String.class);
                    System.out.println(Thread.currentThread() + "请求成功：" + s);
                }
            });
            threads.add(thread);
        }

        for (Thread thread : threads) {
            thread.start();
            thread.join();
        }

        System.out.println("p接口处理完毕");
        return "ok";

    }


    /**
     * 在该接口中，发起多个请求同时访问 test2 接口
     * num代表并发量
     * @return
     */
    @GetMapping("/p1/{num}")
    public String paralTest1(@PathVariable("num") Integer num) throws InterruptedException {

        final RestTemplate restTemplate = new RestTemplate();

        final CountDownLatch latch = new CountDownLatch(num);

        for (int i=0;i<num;i++){
            // 异步执行发送http请求
            new Thread(new Runnable() {
                @Override
                public void run() {
                    final String s = restTemplate.getForObject("http://localhost:8110/test2", String.class);
                    System.out.println(Thread.currentThread() + "请求成功：" + s);
                    latch.countDown();  // 把latch的计数器的值减一
                }
            }).start();
        }

        latch.await();  // 让当前线程阻塞，知道countlatch对象中的计数器的值归零
        System.out.println("p接口处理完毕");
        return "ok";

    }


}
